package com.ideaaedi.zoo.example.springboot.seata_sharding.alpha.service;

import com.ideaaedi.commonspring.transaction.DefaultManualTransactionSupport;
import com.ideaaedi.zoo.example.springboot.seata_sharding.alpha.feign.BetaFeignClient1;
import com.ideaaedi.zoo.example.springboot.seata_sharding.alpha.feign.BetaFeignClient2;
import com.ideaaedi.zoo.example.springboot.seata_sharding.alpha.feign.BetaFeignClient3;
import com.ideaaedi.zoo.example.springboot.seata_sharding.alpha.feign.RawHttpRequest4;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class BizService {
    
    @Resource
    private BizShardingService shardingService;
    
    @Resource
    private BizService bizService;
    
    @Resource
    private BetaFeignClient1 betaFeignClient1;
    
    @Resource
    private BetaFeignClient2 betaFeignClient2;
    
    @Resource
    private BetaFeignClient3 betaFeignClient3;
    
    @Resource
    private RawHttpRequest4 betaFeignClient4;
    
    /**
     * shardingsphere5.5.0整合seata后，正常使用 @Transactional注解即可， 不要有@GlobalTransactional
     */
    @Transactional(rollbackFor = Exception.class)
    public void test() {
        // 1. 本地添加Alpha数据成功
        addSomeAlphaData();
        
        // 2. feign调用beta微服务添加beta数据
        // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
        //betaFeignClient1.addSomeBetaData();
        //betaFeignClient2.addSomeBetaData();
//        OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
        betaFeignClient4.addSomeBetaData();
        
        
        // 3. 本地添加alpha数据后，抛出异常 1 / 0
        addSomeAlphaData();
        System.err.println(1 / 0);// todo 在这里打断点，进入断点后观察两张表的数据；然后放行断点跑完请求，再观察两张表的数据； 对比可知：本地app分库分表分布式事务生效了（，但远程调用的APP产生的数据没有回滚，目前shardingsphere5.5.0暂不支持垮应用全局事务）
    }
    
    
    /**
     * 测试Transactional注解嵌套
     * <p>
     *     结论：可嵌套使用
     * </p>
     */
    @Transactional(rollbackFor = Exception.class)
    public void testNested() {
        addSomeAlphaData();
        
        
        // 2. feign调用beta微服务添加beta数据
        // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
        //betaFeignClient1.addSomeBetaData();
        //betaFeignClient2.addSomeBetaData();
        //OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
        betaFeignClient4.addSomeBetaData();
        
        /*
         * Transactional可以嵌套使用，那么GlobalTransactional是否可以签到使用呢？
         * 这里进行测试
         */
        bizService.addAlphaAndBetaData();
    
        addSomeAlphaData();
        System.err.println(1 / 0);// todo 在这里打断点，进入断点后观察两张表的数据；然后放行断点跑完请求，再观察两张表的数据； 对比可知：本地app分库分表分布式事务生效了（，但远程调用的APP产生的数据没有回滚，目前shardingsphere5.5.0暂不支持垮应用全局事务）
    }
    
    /**
     * 手动事务测试。效果等价于 {@link #test()}
     */
    public void testManual() {
        DefaultManualTransactionSupport.create().voidExec(() -> {
            addSomeAlphaData();
            
            // 2. feign调用beta微服务添加beta数据
            // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
            //betaFeignClient1.addSomeBetaData();
            //betaFeignClient2.addSomeBetaData();
            //OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
            betaFeignClient4.addSomeBetaData();
    
            addSomeAlphaData();
            System.err.println(1 / 0);// todo 在这里打断点，进入断点后观察两张表的数据；然后放行断点跑完请求，再观察两张表的数据； 对比可知：本地app分库分表分布式事务生效了（，但远程调用的APP产生的数据没有回滚，目前shardingsphere5.5.0暂不支持垮应用全局事务）
        });
    }
    
    
    /**
     * 手动事务测试。效果等价于 {@link #testNested()}
     */
    public void testNestedManual() {
        DefaultManualTransactionSupport.create().voidExec(() -> {
            addSomeAlphaData();
            
            // 2. feign调用beta微服务添加beta数据
            // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
            //betaFeignClient1.addSomeBetaData();
            //betaFeignClient2.addSomeBetaData();
            //OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
            betaFeignClient4.addSomeBetaData();
    
            addRandomUserRoleManual();
            
            System.err.println(1 / 0);// todo 在这里打断点，进入断点后观察两张表的数据；然后放行断点跑完请求，再观察两张表的数据； 对比可知：本地app分库分表分布式事务生效了（，但远程调用的APP产生的数据没有回滚，目前shardingsphere5.5.0暂不支持垮应用全局事务）
        });
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void addAlphaAndBetaData() {
        addSomeAlphaData();
        
        // 2. feign调用beta微服务添加beta数据
        // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
        //betaFeignClient1.addSomeBetaData();
        //betaFeignClient2.addSomeBetaData();
        //OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
        betaFeignClient4.addSomeBetaData();
    }
    
    /**
     * 手动事务测试。效果等价于 {@link #addAlphaAndBetaData()}
     */
    public void addRandomUserRoleManual() {
        DefaultManualTransactionSupport.create().voidExec(() -> {
            addSomeAlphaData();
            
            // 2. feign调用beta微服务添加beta数据
            // 示例几种常用的 restful调用远程服务的方式, 这几种方式seata都是支持的； 当然seata还支持更多的restful调用远程服务的方式，详见seata官网
            //betaFeignClient1.addSomeBetaData();
            //betaFeignClient2.addSomeBetaData();
            //OnceFeignProvider.voidExec(() -> betaFeignClient3.addSomeBetaData(), "http://127.0.0.1:8081");
            betaFeignClient4.addSomeBetaData();
            
        });
    }
    
    /**
     * 写入一些数据
     */
    public void addSomeAlphaData() {
        shardingService.insertSomeShardingData(); // 数据库 mysql  demo
    }
}
